package com.koushikdutta.async;

import com.koushikdutta.async.callback.CompletedCallback;
import com.koushikdutta.async.callback.WritableCallback;
import java.nio.ByteBuffer;

public class BufferedDataSink implements DataSink {
    static final /* synthetic */ boolean $assertionsDisabled = (!BufferedDataSink.class.desiredAssertionStatus());
    boolean endPending;
    DataSink mDataSink;
    int mMaxBuffer = Integer.MAX_VALUE;
    ByteBufferList mPendingWrites = new ByteBufferList();
    WritableCallback mWritable;

    public BufferedDataSink(DataSink datasink) {
        setDataSink(datasink);
    }

    public boolean isBuffering() {
        return this.mPendingWrites.hasRemaining();
    }

    public void setDataSink(DataSink datasink) {
        this.mDataSink = datasink;
        this.mDataSink.setWriteableCallback(new WritableCallback() {
            public void onWriteable() {
                BufferedDataSink.this.writePending();
            }
        });
    }

    private void writePending() {
        if (this.mPendingWrites.hasRemaining()) {
            this.mDataSink.write(this.mPendingWrites);
            if (this.mPendingWrites.remaining() == 0 && this.endPending) {
                this.mDataSink.end();
            }
        }
        if (!this.mPendingWrites.hasRemaining() && this.mWritable != null) {
            this.mWritable.onWriteable();
        }
    }

    public void write(ByteBuffer bb) {
        if (remaining() < getMaxBuffer()) {
            boolean needsWrite = true;
            if (!this.mPendingWrites.hasRemaining()) {
                needsWrite = false;
                this.mDataSink.write(bb);
            }
            if (bb.hasRemaining()) {
                ByteBuffer dup = ByteBufferList.obtain(bb.remaining());
                dup.put(bb);
                dup.flip();
                this.mPendingWrites.add(dup);
                if (needsWrite) {
                    this.mDataSink.write(this.mPendingWrites);
                }
            }
        }
    }

    public void write(ByteBufferList bb) {
        write(bb, false);
    }

    protected void write(ByteBufferList bb, boolean ignoreBuffer) {
        if (!this.mPendingWrites.hasRemaining()) {
            this.mDataSink.write(bb);
        }
        if (bb.remaining() > 0) {
            int toRead = Math.min(bb.remaining(), this.mMaxBuffer);
            if (ignoreBuffer) {
                toRead = bb.remaining();
            }
            if (toRead > 0) {
                bb.get(this.mPendingWrites, toRead);
            }
        }
    }

    public void setWriteableCallback(WritableCallback handler) {
        this.mWritable = handler;
    }

    public WritableCallback getWriteableCallback() {
        return this.mWritable;
    }

    public int remaining() {
        return this.mPendingWrites.remaining();
    }

    public int getMaxBuffer() {
        return this.mMaxBuffer;
    }

    public void setMaxBuffer(int maxBuffer) {
        if ($assertionsDisabled || maxBuffer >= 0) {
            this.mMaxBuffer = maxBuffer;
            return;
        }
        throw new AssertionError();
    }

    public boolean isOpen() {
        return this.mDataSink.isOpen();
    }

    public void end() {
        if (this.mPendingWrites.hasRemaining()) {
            this.endPending = true;
        } else {
            this.mDataSink.end();
        }
    }

    public void setClosedCallback(CompletedCallback handler) {
        this.mDataSink.setClosedCallback(handler);
    }
}
